package cn.migu.music.hangupsms.service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableMap;

import cn.migu.music.common.exception.SystemException;
import cn.migu.music.common.utils.DateTimeConvertor;
import cn.migu.music.common.utils.LogUtils;
import cn.migu.music.hangupsms.cachemanage.LocalCacheManager;
import cn.migu.music.hangupsms.cachemanage.event.EventConstants;
import cn.migu.music.hangupsms.common.config.HangUpSmsConfig;
import cn.migu.music.hangupsms.common.entity.OperateBase;
import cn.migu.music.hangupsms.common.entity.SettingOperationEnum;
import cn.migu.music.hangupsms.common.entity.SettingResponse;
import cn.migu.music.hangupsms.common.entity.SmsTemplateOperation;
import cn.migu.music.hangupsms.common.entity.SmsTemplateSettings;
import cn.migu.music.hangupsms.repository.HangupMsgSendUserMapper;
import cn.migu.music.hangupsms.repository.SmsTemplateSettingsMapper;
import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class SmsTemplateSettingsService implements SettingsApplyHandler {
    private static final String              TONE_PREFIX  = "t:";
    private static final String              TX_PREFIX    = "smsTemplate";
    private static final String              OP_TABLE     = "t_migu_hangup_sms_template";
    private static final Map<String, String> SMS_TYPE_MAP = ImmutableMap.of("普通用户", "00", "视频彩铃用户", "10", "视频彩铃会员", "11");
    @Autowired
    private SmsTemplateSettingsMapper        templateSettingsMapper;
    @Autowired
    private HangupMsgSendUserMapper          hangupMsgSendUserMapper;
    @Autowired
    private SettingsChangeLogService         changeLogService;
    @Autowired
    private LocalCacheManager                cacheManager;
    @Autowired
    private HangUpSmsConfig                  hangUpSmsConfig;

    @PostConstruct
    public void init() {
        changeLogService.registerApply(TX_PREFIX, this);
    }

    /**
     * 新增短信模板配置
     * 
     * @param opList
     * @return
     */
    @Transactional
    @PostMapping("/hangupsms/settings/sms-template/add/v1.0")
    public SettingResponse<List<String>> addSmsTemplate(@RequestBody List<SmsTemplateOperation> opList) {
        SettingResponse<List<String>> response = new SettingResponse<>();
        int count = 1;
        List<SmsTemplateOperation> opDoneList = new ArrayList<>();
        for (SmsTemplateOperation operation : opList) {
            String templateId = operation.getTemplateId();
            String content = operation.getTemplateContent();
            if (StringUtils.isEmpty(templateId) || StringUtils.isEmpty(content)) {
                response.setResultCode(SettingResponse.ERROR_CODE);
                response.setResultMessage("短信模板参数错误:第" + count + "条");
                return response;
            }
            if (StringUtils.contains(templateId, ":")) {
                String[] cls = StringUtils.split(templateId, ":");
                templateId = cls[0] + SMS_TYPE_MAP.get(cls[1]);
            }
            SmsTemplateOperation newOp = new SmsTemplateOperation();
            BeanUtils.copyProperties(operation, newOp);
            newOp.setTemplateId(templateId);
            opDoneList.add(newOp);
        }
        List<SmsTemplateSettings> settingsList = new ArrayList<>(opList.size());
        List<String> txList = new ArrayList<>(opList.size());
        for (SmsTemplateOperation operation : opDoneList) {
            String templateId = operation.getTemplateId();
            String content = operation.getTemplateContent();
            SmsTemplateSettings settings = new SmsTemplateSettings();
            settings.setTemplateId(templateId);
            settings.setTemplateContent(content);
            settings.setApplyStatus(0);
            settings.setDeleteFlag(0);
            settings.setChangeTime(LocalDateTime.now());
            settingsList.add(settings);
            String txId = TX_PREFIX + "." + templateId;
            txList.add(txId);
        }
        try {
            addToDb(settingsList, opList);
        } catch (Exception e) {
            LogUtils.error(e, log, "save db error");
            response.setResultCode(SettingResponse.ERROR_CODE);
            response.setResultMessage(e.getMessage());
            return response;
        }
        response.setData(txList);
        response.setResultCode(SettingResponse.SUCCESS_CODE);
        response.setResultMessage(SettingResponse.SUCCESS_MSG);
        return response;
    }

    /**
     * 删除短信模板
     * 
     * @param templateId
     *            短信模板ID
     */
    @GetMapping("/hangupsms/settings/sms-template/del/v1.0")
    @Transactional
    public void delete(@RequestParam String templateId) {
        templateSettingsMapper.remove(templateId);
        String shortId = getShortId(templateId);
        if (StringUtils.isNotEmpty(shortId)) {
            templateSettingsMapper.remove(TONE_PREFIX + templateId);
        }
        cacheManager.broadcastEvent(EventConstants.SMS_TEMPLATE_CHANGED_EVNET);
    }

    @Transactional
    public void addToDb(List<SmsTemplateSettings> settingsList, List<SmsTemplateOperation> opList) {
        templateSettingsMapper.batchInsert(settingsList);
        for (int i = 0; i < settingsList.size(); ++i) {
            SmsTemplateSettings settings = settingsList.get(i);
            buildShortId(settings.getTemplateId());
            OperateBase operateBase = opList.get(i);
            operateBase.setOperationEnum(SettingOperationEnum.ADD);
            changeLogService.addLog(operateBase, OP_TABLE, settings.getTemplateId(), "", JSON.toJSONString(settings));
        }
    }

    private String getShortId(String longTemplateId) {
        SmsTemplateSettings configSetting = templateSettingsMapper.get(TONE_PREFIX + longTemplateId);
        if (configSetting != null) {
            return configSetting.getTemplateContent();
        }
        return null;
    }

    private void buildShortId(String templateId) {
        if (StringUtils.length(templateId) == 20) {
            SmsTemplateSettings configSetting = templateSettingsMapper.get(TONE_PREFIX + templateId);
            if (configSetting != null) {
                return;
            }
            List<SmsTemplateSettings> settingList = templateSettingsMapper.getLike(TONE_PREFIX + "%");
            int shortId = findAbsentId(settingList);
            if (shortId == -1) {
                throw SystemException.newInstance("铃音短信过多，请先清除多余的铃音");
            }
            SmsTemplateSettings settings = new SmsTemplateSettings();
            settings.setTemplateContent(String.valueOf(shortId));
            settings.setTemplateId(TONE_PREFIX + templateId);
            settings.setApplyStatus(1);
            settings.setChangeTime(LocalDateTime.now());
            settings.setDeleteFlag(0);
            settings.setApplyTime(LocalDateTime.now());
            templateSettingsMapper.insert(settings);
        }
    }

    private int findAbsentId(List<SmsTemplateSettings> settingList) {
        if (CollectionUtils.isEmpty(settingList)) {
            return 8000;
        }
        Set<Integer> numberSet = new HashSet<>();
        int maxId = -1;
        for (SmsTemplateSettings settings : settingList) {
            int id = Integer.parseInt(settings.getTemplateContent());
            numberSet.add(id);
            if (id > maxId) {
                maxId = id;
            }
        }
        if (maxId < 8000) {
            return -1;
        }
        for (int i = 8000; i <= maxId; ++i) {
            if (!numberSet.contains(i)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 修改短信模板配置
     * 
     * @param op
     * @return
     */
    @Transactional
    @PostMapping("/hangupsms/settings/sms-template/edit/v1.0")
    public SettingResponse<String> updateSmsTemplate(@RequestBody SmsTemplateOperation op) {
        SettingResponse<String> response = new SettingResponse<>();
        if (StringUtils.isEmpty(op.getTemplateId()) || StringUtils.isEmpty(op.getTemplateContent())) {
            response.setResultCode(SettingResponse.ERROR_CODE);
            response.setResultMessage("短信模板参数错误");
            return response;
        }

        SmsTemplateSettings settings = templateSettingsMapper.get(op.getTemplateId());
        if (settings == null || settings.getDeleteFlag() == 1) {
            response.setResultCode(SettingResponse.ERROR_CODE);
            response.setResultMessage("短信模板不存在：" + op.getTemplateId());
            return response;
        }
        SmsTemplateSettings newSettings = new SmsTemplateSettings();
        newSettings.setTemplateId(settings.getTemplateId());
        newSettings.setApplyStatus(0);
        newSettings.setChangeTime(LocalDateTime.now());
        newSettings.setTemplateContent(op.getTemplateContent());
        try {
            templateSettingsMapper.updateTime(newSettings);
            OperateBase operateBase = op;
            operateBase.setOperationEnum(SettingOperationEnum.EDIT);
            changeLogService.addLog(operateBase, OP_TABLE, settings.getTemplateId(), JSON.toJSONString(newSettings), JSON.toJSONString(settings));
        } catch (Exception e) {
            LogUtils.error(e, log, "insert data error.");
            response.setResultMessage("error:" + e.getMessage());
            response.setResultCode(SettingResponse.ERROR_CODE);
            return response;
        }
        response.setResultCode(SettingResponse.SUCCESS_CODE);
        response.setResultMessage(SettingResponse.SUCCESS_MSG);
        String txId = TX_PREFIX + "." + settings.getTemplateId();
        response.setData(txId);
        return response;
    }

    /**
     * 查询短信模板配置
     * 
     * @param provinceId
     *            省编码
     * @return
     */
    @GetMapping("/hangupsms/settings/sms-template/display/v1.0")
    public SettingResponse<List<SmsTemplateSettings>> getSmsTemplates(@RequestParam String provinceId) {
        SettingResponse<List<SmsTemplateSettings>> response = new SettingResponse<>();
        response.setResultCode(SettingResponse.SUCCESS_CODE);
        if (StringUtils.isEmpty(provinceId)) {
            List<SmsTemplateSettings> settingsList = templateSettingsMapper.getAllSettings();
            List<SmsTemplateSettings> provinceSmsList = new ArrayList<>();
            for (SmsTemplateSettings settings : settingsList) {
                if (StringUtils.length(settings.getTemplateId()) == 20 || StringUtils.startsWith(settings.getTemplateId(), TONE_PREFIX)) {
                    continue;
                }
                provinceSmsList.add(settings);
            }
            response.setData(provinceSmsList);
            return response;
        }
        if (StringUtils.equals("toneSms", provinceId)) {
            List<SmsTemplateSettings> settingsList = templateSettingsMapper.getAllSettings();
            List<SmsTemplateSettings> toneSmsList = new ArrayList<>();
            for (SmsTemplateSettings settings : settingsList) {
                if (StringUtils.length(settings.getTemplateId()) == 20) {
                    toneSmsList.add(settings);
                }
            }
            response.setData(toneSmsList);
        } else {
            List<SmsTemplateSettings> settingsList = templateSettingsMapper.getByProvince(provinceId + "%");
            response.setData(settingsList);
        }
        return response;
    }

    /**
     * 统计短信模板配置
     * 
     * @param templateId
     *            模板id
     * @param startTime
     *            开始时间
     * @param endTime
     *            结束时间
     * @return
     */
    @GetMapping("/hangupsms/settings/sms-template/static/v1.0")
    public SettingResponse<Integer> getSmsTemplateCount(@RequestParam String templateId,
                                                        @RequestParam String startTime,
                                                        @RequestParam String endTime) {
        SettingResponse<Integer> response = new SettingResponse<>();
        response.setResultCode(SettingResponse.SUCCESS_CODE);
        Set<String> provinceSet = hangUpSmsConfig.getProvinceAndLocalIdMap().keySet();
        String provinceId = StringUtils.substring(templateId, 0, 2);
        String pattern = "yyyy-MM-dd";
        Date startDate = DateTimeConvertor.parse(startTime, pattern);
        Date endDate = DateTimeConvertor.parse(endTime, pattern);
        response.setData(0);
        if (StringUtils.length(templateId) == 4 && provinceSet.contains(provinceId)) {
            String localId = hangUpSmsConfig.getProvinceAndLocalIdMap().get(provinceId);
            int count = hangupMsgSendUserMapper.getSendCount(Integer.parseInt(localId), templateId, startDate, endDate);
            response.setData(count);
            return response;
        }
        if (StringUtils.length(templateId) == 20) {
            int count = hangupMsgSendUserMapper.getSendCountNoLocalId(getShortId(templateId), startDate, endDate);
            response.setData(count);
        }
        return response;
    }

    @Override
    public boolean apply(String rowId, String user) {
        SmsTemplateSettings settings = templateSettingsMapper.get(rowId);
        if (settings != null) {
            templateSettingsMapper.updateApplyStatus(rowId, 1, LocalDateTime.now());
            SmsTemplateSettings updatedSettings = templateSettingsMapper.get(rowId);
            if (updatedSettings.getApplyStatus() != 1) {
                return false;
            }
            cacheManager.broadcastEvent(EventConstants.SMS_TEMPLATE_CHANGED_EVNET);
            OperateBase operateBase = new OperateBase();
            operateBase.setOperationEnum(SettingOperationEnum.APPLY);
            operateBase.setOperateUser(user);
            changeLogService.addLog(operateBase, OP_TABLE, settings.getTemplateId(), JSON.toJSONString(updatedSettings), JSON.toJSONString(settings));
            return true;
        }
        return false;
    }
}
